/*
 * fat.c
 *
 *  Created on: 19/11/2011
 *      Author: utn_so
 */

#include "fat.h"

extern t_pfs pPfs;


int cantidadTotalDeSectores(void){
	return(pPfs.fat32.bootSector.totalSectors ==0?pPfs.fat32.bootSector.totalSectorsExt:pPfs.fat32.bootSector.totalSectors);
}

int32_t cantidadTotalDeClusters(void){
return	(cantidadTotalDeSectores()/pPfs.fat32.bootSector.sectorsPerCluster);

}

/*
 * @NAME: cargarFat
 * @DESC: Carga la fat en memoria
 */
int cargarFat(void){


char *fatFile;
int sizeFites;
int sizeFdt;
int i=0;
t_file_block * fileBlock;


int32_t cantidadDeSectoresAPedir=ceil((cantidadTotalDeClusters()*4)/512);
int32_t sectorInicialFat=pPfs.fat32.bootSector.reservedSectorCount;
t_list * listaSectoresFat;
pPfs.fat32.fat = (t_fat32 *)malloc(sizeof(t_fat32));
pPfs.fat32.fat->tabla = (char *)malloc(cantidadTotalDeClusters());


listaSectoresFat=collection_list_create();

for(i=0;i<cantidadDeSectoresAPedir;i++){
	t_sector * sector;
	sector = pedirSector(i+sectorInicialFat);
	collection_list_add(listaSectoresFat,sector);
}


i=0;
int cargado=0;
int cantidadTotalACargar = cantidadTotalDeClusters()*4;
int cantidadACargar;

while(i<listaSectoresFat->elements_count && cargado < cantidadTotalACargar){
	t_sector * sector;
	sector = collection_list_get(listaSectoresFat,i);
	if((cantidadTotalACargar - cargado )<512){
		cantidadACargar = cantidadTotalACargar - cargado;
	}else{
		cantidadACargar = 512;
	}
	cargado = cargado + cantidadACargar;
	memcpy(pPfs.fat32.fat->tabla,sector->data,cantidadACargar);
}
while(listaSectoresFat->elements_count){
	t_sector * sector = collection_list_remove(listaSectoresFat,0);
	freeSector(sector);
}
free(listaSectoresFat);

pPfs.fat32.fat->contador=0;
return 1;
}

/*
 * @NAME: fatEntryValues
 * @DESC: Pasandole el valor en la fat, devuelve que tipo de entrada es y en caso de estar concatenado, cluster devuelve el siguiente valor
 */
int32_t fatEntryValues(void * valor,int *cluster){
	uint32_t * valorEntrada2= (uint32_t *) valor;
	uint32_t valorEntrada= *valorEntrada2;

	if(valorEntrada==0x00000000) return FREE_CLUSTER;
	if(valorEntrada == 0x00000001)return RESERVED;
	if(valorEntrada>=0x00000002 && valorEntrada<= 0x0FFFFFEF) {
		*cluster=valorEntrada;
		return USED_CLUSTER;
	}
	if(valorEntrada>=0x0FFFFFF0 && valorEntrada<= 0x0FFFFFF5) return RESERVED2;
	if(valorEntrada==0x0FFFFFF6) return RESERVED3;
	if(valorEntrada==0x0FFFFFF7) return BAD_SECTOR;
	if(valorEntrada>=0x0FFFFFF8 && valorEntrada<= 0xFFFFFFFF) {
	//	*cluster=valorEntrada;
		return LAST_CLUSTER_IN_FILE;
	}

return RESERVED;

}
//TODO : VER DONDE PONER
/*
 * @NAME: calcularSizeOfSystemArea
 * @DESC: Devuelve el area, es lo que ocupa la fat, sin contar la fdt (o contandola?)
 */
int calcularSizeOfSystemArea(void){
int SSA,RSC,FN,SF,RDE,SS;
RSC=pPfs.fat32.bootSector.reservedSectorCount;
FN=pPfs.fat32.bootSector.numberOfFATS;
SF=pPfs.fat32.extendBios.sectorsFAT;
RDE=pPfs.fat32.bootSector.numberOfRootDirectoriesEntries;
SS=pPfs.fat32.bootSector.bytesPerSector;

SSA=RSC+FN*SF+ceil((32*RDE)/SS);
return SSA;

}

//TODO VER DONDE PONER
/*
 * @NAME: CalclularLogicalSectorNumber
 * @DESC: Le pasas el numero de cilindro y te devuelve en que sector comienza

 */
int calcularLogicalSectorNumber(int CN){
int SSA,LSN,SC;
SSA=calcularSizeOfSystemArea();
SC=pPfs.fat32.bootSector.sectorsPerCluster;
LSN=SSA+(CN-2)*SC;
printf("MIERDA SSA: %d MIERDA SC %d  MIERDA LSN %d",SSA,SC,LSN);
return LSN;
}



/*
 * @NAME: fdtStartSector
 * @DESC: Devuelve el sector donde comienza la fdt
 */

int fdtStartSector(void){
	int fdtStartSector=0;

	fdtStartSector= pPfs.fat32.bootSector.reservedSectorCount+
			pPfs.fat32.extendBios.sectorsFAT *
			pPfs.fat32.bootSector.numberOfFATS +
							(pPfs.fat32.extendBios.clusterRootDirectory -2)*
							pPfs.fat32.bootSector.sectorsPerCluster;

	return fdtStartSector;
}

//void obtenerFileDataEntryDe(char * fileName,t_fdtLongEntry * fdtEntry){
//}

/*
 * @NAME: clusterInicialDeFat
 * @DESC: clusterInicialDeFat
 */
int clusterInicialDeFat(void){
	int cantidadDeClustersQueOcupa1Fat=0;
	int clusterInicial=0;
	cantidadDeClustersQueOcupa1Fat=	ceil(pPfs.fat32.extendBios.sectorsFAT/pPfs.fat32.bootSector.sectorsPerCluster);
	printf("cant cluster ocupa far %d \n",cantidadDeClustersQueOcupa1Fat);
//	clusterInicial= ceil(calcularSizeOfSystemArea(fat32)/fat32.bootSector.sectorsPerCluster)-cantidadDeClustersQueOcupa1Fat*2;
	clusterInicial= ceil(calcularSizeOfSystemArea()/pPfs.fat32.bootSector.sectorsPerCluster)-cantidadDeClustersQueOcupa1Fat*2;
	printf("Clusters SSA %d \n",clusterInicial);

return clusterInicial;


}

/*
 * @NAME: sectorInicialDeFdt
 * @DESC: Devuelve el sector Inicial de Fdt
 */
int sectorInicialDeFdt(void){
	printf("cluster inicial de fat %d",clusterInicialDeFat());
	printf("sectores por cluster %d",pPfs.fat32.bootSector.sectorsPerCluster);
return clusterInicialDeFat()*pPfs.fat32.bootSector.sectorsPerCluster;
}

//Devuelve la lista con los nClusters libres o una lista vacia si no llega a encontrar la cantidad todal
t_list * listaNClustersLibres(uint32_t cantidad){
	uint32_t cantidadEncontrada=0;
	uint32_t nClusterActual=0;
	int32_t clusterSiguiente;
	uint32_t *nClusterAlista;
	t_list * listaNClustersLibres=collection_list_create();

	while(nClusterActual < cantidadTotalDeClusters() && cantidadEncontrada < cantidad){
		if(fatEntryValues(&pPfs.fat32.fat->tabla[nClusterActual],&clusterSiguiente)==FREE_CLUSTER){
			nClusterAlista = (uint32_t *)malloc(sizeof(uint32_t));
			*nClusterAlista = nClusterActual;
			collection_list_add(listaNClustersLibres,nClusterAlista);
			cantidadEncontrada++;
	}
nClusterActual++;
}
	if(cantidadEncontrada < cantidad){
		while(listaNClustersLibres->elements_count!=0){
			nClusterAlista = collection_list_remove(listaNClustersLibres,0);
			free(nClusterAlista);
		}

	}
	return listaNClustersLibres;
}
/*
 * @NAME: listaClustersLibres

 * @DESC: Devuelve una lista con los numeros de clustersLibres
 */
t_list * listaClustersLibres(void){
	int i=0;
	int posCluster=0;
	t_list * listaClustersLibres = collection_list_create();
	int32_t cluster=0;
	while(cluster<cantidadTotalDeClusters()){

		if(fatEntryValues(&pPfs.fat32.fat->tabla[posCluster],&i)==FREE_CLUSTER){
			printf("Cluster libre %d \n",cluster);
			fflush(stdin);
			int32_t * clusterLibre = (int32_t *) malloc(sizeof(int32_t));
			*clusterLibre = cluster;
			collection_list_add(listaClustersLibres,clusterLibre);

		}
		posCluster = posCluster +4;
		cluster++;
	}
return listaClustersLibres;
}

int32_t extenerNCluster(int32_t cantClusters, int32_t clusterActual){
	t_list * listaClustersLibres = listaNClustersLibres(cantClusters);

	if(listaClustersLibres->elements_count ==0){
		return 0;
	}
	uint32_t clusterNuevo = clusterActual;
	while(listaClustersLibres->elements_count){
		uint32_t * clusterEnLista = collection_list_remove(listaClustersLibres,0);
		pPfs.cacheArchivos.fat->tabla[clusterNuevo]= *clusterEnLista;
		clusterNuevo=*clusterEnLista;
		free(clusterEnLista);
	}
	pPfs.cacheArchivos.fat->tabla[clusterNuevo]= LAST_CLUSTER_IN_FILE;
	free(listaClustersLibres);
	return clusterNuevo;
}

//TODO mismo nombre, fijarse si se necesita el archivo padre

void agregarPrimerCluster(t_cache_archivo * archivo){
tomarFat();
tomarCache();
t_list * listaClusterLibre = listaNClustersLibres(1);
int32_t * nClusterLibre = collection_list_remove(listaClusterLibre,0);
archivo->entradaDelArchivo->entradaCorta.startCluster = *nClusterLibre;
pPfs.cacheArchivos.fat->tabla[*nClusterLibre]= LAST_CLUSTER_IN_FILE;
free(nClusterLibre);
free(listaClusterLibre);
liberarCache();
liberarFat();

}

void removerPrimerCluster(t_cache_archivo * archivo){
	tomarFat();
	pPfs.cacheArchivos.fat->tabla[archivo->entradaDelArchivo->entradaCorta.startCluster] =0;
	liberarFat();
	archivo->entradaDelArchivo->entradaCorta.startCluster =0;
}
///SACADO PARA QUE COMPILE
/*
uint32_t cantidadDeClusterAgregar(uint32_t tamanioNuevo, uint32_t tamanioViejo){
	uint32_t clustersNecesarios;
	uint32_t clusterExtra =(tamanioNuevo % (bytesPerCluster()) == 0) ? -1 : 0;
	if (tamanioViejo % (bytesPerCluster * pPfs.fat32.bootSector.bytesPerSector)==0)
		clusterExtra++;
	clustersNecesarios = (tamanioNuevo / bytesPerCluster()
			- tamanioViejo/bytesPerCluster()) + clusterExtra;
	return clustersNecesarios;
}
*/


//NUEVO
//Opcion indica si puede asignar un nuevo cluster
//TODO cambiado busca tamaño libre y bien
uint32_t * buscarPosLibreEnLibreEnDir(t_fdtCompleteEntry * entradaLibre, t_fdtCompleteEntry * entradaDir,int32_t *tamanioPedido,char * cluster, int32_t opcion){
	int32_t encontrado =0;
	uint32_t entradaEsParcial = 0;
	uint32_t bytesAnalizados=0;
	uint32_t pos = 0;
	int32_t creoNuevoCLuster =0;
	uint32_t nClusterAnterior;
	uint32_t nClusterActual = entradaDir->entradaCorta.startCluster;
	uint32_t creoNuevoCluster=0;

	//TODO: el no encontrado no lo toco....mmm..suena feo
	while(!encontrado){
		cluster =	pedirCluster(nClusterActual);

		while(bytesAnalizados < bytesPerCluster()){
			t_fdtCompleteEntry * entradaAux;
				memcpy(&entradaAux->entradaCorta,&cluster[bytesAnalizados],32);

				//Me fijo si la entrada esta borrada
				if(entradaAux->entradaCorta.DOSFilename[0]==0 ||
					entradaAux->entradaCorta.DOSFilename =='E5')
					//Si el tamaño a pedir es 32, devuelvo la posicion
					if(entradaEsParcial){
						*cluster = nClusterAnterior;
						return bytesAnalizados-32;
					}
					if(tamanioPedido == 32){
						return bytesAnalizados;
					}
				//Si lei la ultima entrada del cluster y necesito una entrada mayor activo un flag
				if(bytesAnalizados==bytesPerCluster()){
					entradaEsParcial=1;
				}
				if(!entradaEsParcial){
						//Aca entra si necesita una entrada de 64.
						bytesAnalizados = bytesAnalizados +32;

						memcpy(&entradaAux->entradaCorta,&cluster[bytesAnalizados],32);
						if(entradaAux->entradaCorta.DOSFilename[0]==0 ||
							entradaAux->entradaCorta.DOSFilename =='E5'){
							*cluster = nClusterActual;
							return bytesAnalizados;
						}
						bytesAnalizados = bytesAnalizados +32;
					//Si esta aca es porque la siguiente entrada es valida, por lo cual hay que continuar leyendo
				}

				}
				free(cluster);
				//Si llego aca es porque necesito un cluster mas, si es el ultimo cluster lo extiendo,
				//sino pido otro
				if(opcion){
				nClusterAnterior = nClusterActual;
				if(fatEntryValues(pPfs.fat32.fat->tabla[nClusterActual],&nClusterActual)==LAST_CLUSTER_IN_FILE){
					nClusterActual = extenerNCluster(1,nClusterActual);
					creoNuevoCluster=1;
				//TODO ojo que si extender Cluster devuelve 0 es que fallo
				}
				}
				if(!creoNuevoCLuster){

				cluster = leerCluster(nClusterActual);
				}else{
					cluster = (char *) malloc(bytesPerCluster());
					memset(cluster,0,bytesPerCluster());
				}
		}



	}


/*
 * @NAME: extenderCluster
 * @DESC: Pasandole un numero de Cluster, este busca un cluster libre y lo extiende, si no se puede realizar la operacion devuelve 0
 */
int32_t extenderCluster(int32_t nCluster){
t_list * lClustersLibres;

lClustersLibres = listaClustersLibres();

if(!lClustersLibres->elements_count){
	return 0;
}


int * unClusterLibre = collection_list_get(lClustersLibres,0);

pPfs.fat32.fat->tabla[nCluster]=*unClusterLibre;
pPfs.fat32.fat->tabla[*unClusterLibre]=LAST_CLUSTER_IN_FILE;

collection_list_clean(lClustersLibres,free);

free(lClustersLibres);
return 1;
}

/*
 * @NAME: obtenerTablaFat
 * @DESC: Esta funcion deberia usarse para acceder a la fat para controlar su sincronizacion
 */
char * obtenerTablaFat(void){

if(pPfs.fat32.fat->contador == 100){
	reloadFat();
}
pPfs.fat32.fat->contador ++;
return pPfs.fat32.fat->tabla;

}

/*
 * @NAME: reloadFat
 * @DESC: Esta funcion deberia mantener consistente la fat. Deberia escribir la fat a disco
 */
int32_t reloadFat(void){
free(pPfs.fat32.fat);
cargarFat();
return 1;
}

/*
 * @NAME: escribirFat
 * @DESC: Escribe el valor en la posicion de la fat
 *///NO QUEDA
/*
int32_t escribirFat(int32_t posicion,int32_t valor){
	//TODO: Trabar la fat
	pPfs.fat32.fat->tabla[posicion]= valor;
	escribirFatEnDisco();
	return 1;
}
*/

/*
 * @NAME: escribirFatEnDisco
 * @DESC: Escribe la fat en disco....obvio
 */
int32_t escribirFatEnDisco(void){
	FILE * pFile;
		  pFile = fopen ("/home/utn_so/Escritorio/fat32.disk4","w");
		  if (pFile!=NULL)
		  {
		    fwrite(pPfs.fat32.fat->tabla,1,cantidadTotalDeClusters(),&pFile[(sectorInicialDeFdt()-1)]);
		    fclose (pFile);
		  }
return 1;
}

/* V1
t_list * clusterConcatenadosDeCluster(int32_t nCluster){
	t_list * listaClustersConcatenados = collection_list_create();
	t_cluster * clusterConcatenado;
	int nClusterConcatenado = 0;
	int32_t tipoCluster;


	tipoCluster=fatEntryValues(&pPfs.fat32.fat->tabla[nCluster],&nClusterConcatenado);

	if(tipoCluster ==LAST_CLUSTER_IN_FILE){
		clusterConcatenado = armarCluster(nCluster);
		collection_list_add(listaClustersConcatenados,clusterConcatenado);
		return listaClustersConcatenados;
	}

	clusterConcatenado = armarCluster(nCluster);
	collection_list_add(listaClustersConcatenados,clusterConcatenado);


	while(tipoCluster ==USED_CLUSTER){

				clusterConcatenado = armarCluster(nClusterConcatenado);
				collection_list_add(listaClustersConcatenados,clusterConcatenado);
				nCluster=nClusterConcatenado;
				tipoCluster=fatEntryValues(&pPfs.fat32.fat->tabla[nCluster],&nClusterConcatenado);
	}

	return listaClustersConcatenados;

}
*/

/*
 * @NAME: clusterConcatenadosDeCluster
 * @DESC: Pasandole un cluster devuelve una lista de los numeros de clusters concatenados al mismo
 */
t_list * clusterConcatenadosDeCluster(int32_t nCluster){
	t_list * listaClustersConcatenados = collection_list_create();
	int32_t * clusterConcatenado;
	int nClusterConcatenado = 0;
	int32_t tipoCluster;


	tipoCluster=fatEntryValues(&pPfs.fat32.fat->tabla[nCluster],&nClusterConcatenado);

	if(tipoCluster ==LAST_CLUSTER_IN_FILE){
		clusterConcatenado = (int32_t *)malloc(sizeof(int32_t));
		*clusterConcatenado =nCluster;
		collection_list_add(listaClustersConcatenados,clusterConcatenado);
		return listaClustersConcatenados;
	}

	clusterConcatenado = (int32_t *)malloc(sizeof(int32_t));

	*clusterConcatenado =nCluster;
	collection_list_add(listaClustersConcatenados,clusterConcatenado);


	while(tipoCluster ==USED_CLUSTER){
		clusterConcatenado = (int32_t *)malloc(sizeof(int32_t));
				*clusterConcatenado =nClusterConcatenado;
				collection_list_add(listaClustersConcatenados,clusterConcatenado);
				nCluster=nClusterConcatenado;
				tipoCluster=fatEntryValues(&pPfs.fat32.fat->tabla[nCluster],&nClusterConcatenado);
	}

	return listaClustersConcatenados;

}



/*
/*
 * @NAME: fdtEntryDePath
 * @DESC: Pasandole un path devuelve la entrada de la fdt del mismo. Usa cache cuando corresponde.
 *///GUARDA, HAY QUE INICIALIZAR ANTES EL COMPLETE ENTRY Y EL ARCHIVO CACHE
/*
int32_t fdtEntryDePath(char * path,t_fdtCompleteEntry * fdtEntry,t_cache_archivo * entradaCache){
int32_t encontrado=0;
int32_t encontradoPadre=0;

t_cache_archivo * archivoEnCache;
t_cache_archivo * archivoPadreEnCache;
//t_cache_archivo * archivoPadreEnCache = (t_cache_archivo *)malloc(sizeof(t_cache_archivo));
//fdtEntry = (t_fdtCompleteEntry *)malloc(sizeof(t_fdtCompleteEntry));

printf("En fdtEntryDePath \n");
printf("Nombre Archivo: %s \n",path);
fflush(stdin);

	if(cacheActivada()){
		t_cache_archivo * archivoEnCache;
		encontrado = buscarArchivoEnCache(path,archivoEnCache);
		if(!encontrado){
			encontradoPadre = buscarArchivoPadreEnCache(path,archivoPadreEnCache);
		}

		if(encontradoPadre){
			encontrado = buscarFdtEntryEnDiscoDesdePadre(path,archivoPadreEnCache,archivoEnCache);
		}
		else{
			printf("En fdtEntryDePath \n");
			printf("Nombre Archivo: %s \n",path);
			fflush(stdin);

			encontrado = buscarFdtEntryEnDisco(path,fdtEntry);
					//TODO: agregar copaiado a cache

		}
	}
//TODO: copiar coso


	if(!encontrado && !cacheActivada()){

		encontrado = buscarFdtEntryEnDisco(path,fdtEntry);
	}
	return encontrado;
}
*/
/*
 * @NAME: buscarFdtEntryEnDiscoDesdePadre
 * @DESC: Busca recursivamente hacia atras en la cache la entrada en cache del directorio padre
 */
int32_t buscarFdtEntryEnDiscoDesdePadre(char * path, t_cache_archivo *archivoPadreEnCache, t_cache_archivo *archivoEnCache){
	char * pathFaltante;
	int32_t i=0;
	int32_t encontrado = 0;
	t_array * arrayPathFaltante;
	t_cache_archivo * entradaParcial;

	while(archivoPadreEnCache->pathYNombreDelArhivo[i] != archivoEnCache->pathYNombreDelArhivo[i]){
		i++;
	}
	arrayPathFaltante = scanner_split2(&archivoPadreEnCache->pathYNombreDelArhivo[i],'/');


	while(i<arrayPathFaltante->size ||  !encontrado){
	char * dir =	array_get(arrayPathFaltante,i);
	encontrado  = buscarFdtEntryEnDiscoEnDirectorio(dir,entradaParcial);
	}
	if(encontrado){
		crearCacheParaPath(path,entradaParcial->entradaDelArchivo);
		archivoEnCache = entradaParcial;
	}


	return encontrado;
}

int32_t buscarFdtEntryEnDisco(char * path, t_fdtCompleteEntry * fdtEntry){
t_array * arrayPath = obtenerArrayPathDePath(path);
int32_t i=1;
t_fdtCompleteEntry * entradaArchivo;
t_fdtCompleteEntry * entradaParcial;
entradaParcial = (t_fdtCompleteEntry *)malloc(sizeof(t_fdtCompleteEntry));
int32_t encontrado;

printf("%s / %s \n",arrayPath->data[1],arrayPath->data[2]);
fflush(stdin);

while(i<arrayPath->size){
char * dir;

dir =(char *) malloc(strlen(arrayPath->data[i]));
strcpy(dir,arrayPath->data[i]);

printf("Path pipi %s \n",dir);
fflush(stdin);
if(i==1){
	encontrado = buscarFdtEntryEnRoot(dir,entradaParcial);
	if(!encontrado){
		return 0;
	}
}
else{

encontrado  = buscarFdtEntryEnDiscoEnDirectorio(dir,entradaParcial);
if(!encontrado){
	return 0;
}
}
printf("%s / %s \n",arrayPath->data[1],arrayPath->data[2]);
fflush(stdin);
//TODO: buscar el resto
i++;
printf("%s / %s \n",arrayPath->data[1],arrayPath->data[2]);
fflush(stdin);
free(dir);
}
memcpy(&fdtEntry->entradaCorta,&entradaParcial->entradaCorta, sizeof(t_fdtEntry));
memcpy(&fdtEntry->entradaLarga,&entradaParcial->entradaLarga,sizeof(t_fdtLongEntry));


int j=0;

free(entradaParcial);
while(i<arrayPath->size){
//	printf("pipi %s \n",array_get(arrayPath,i));
//	fflush(stdin);
	free(array_get(arrayPath,i));
	free(arrayPath->data);
j++;
j=0;
}
free(arrayPath);
return 1;
}

/*
 * @NAME: obtenerArrayPathDePath
 * @DESC: Pasandole un path, lo descompone en un array
 */
t_array * obtenerArrayPathDePath(char * path){
t_array * arrayPath =	scanner_split2(path,'/');
printf("%s / %s \n",arrayPath->data[1],arrayPath->data[2]);
fflush(stdin);
return arrayPath;
}

/*
 * @NAME: buscarFdtEntryEnRoot
 * @DESC: Busca una entrada en la Fdt del root que siempre esta en memoria principal
 */
int32_t buscarFdtEntryEnRoot(char *nombreArchivo, t_fdtCompleteEntry * entradaArchivo){
int32_t clusterAnalizado=0;
int32_t encontrado=0;
t_cluster * clusterAAnalizar;
printf("En buscarFdtEntryEnRoot \n");
printf("Nombre Archivo: %s \n",nombreArchivo);
fflush(stdin);

while((!encontrado) && (clusterAnalizado < pPfs.cacheArchivos.root.listaClusters->elements_count)){
clusterAAnalizar = collection_list_get(pPfs.cacheArchivos.root.listaClusters,clusterAnalizado);
	encontrado = buscarFdtEntryEnCluster(entradaArchivo,clusterAAnalizar,nombreArchivo);
}

return encontrado;
}

/*
 * @NAME: buscarFdtEntryEnDiscoEnDirectorio
 * @DESC: Busca un directorio que debe estar en la entradaParcial, OJO no deberia devolver la entrada encontrada?
 */
int32_t buscarFdtEntryEnDiscoEnDirectorio(char * dir,t_fdtCompleteEntry *entradaParcial){
	int32_t encontrado =0;
	t_list * listaDeClustersARevisar;
	t_cluster * clusterARevisar;
	int32_t nClusterARevisar;

	listaDeClustersARevisar = clusterConcatenadosDeCluster(entradaParcial->entradaCorta.startCluster);
	nClusterARevisar=0;
	while((!encontrado) && (nClusterARevisar<listaDeClustersARevisar->elements_count)){


	clusterARevisar = collection_list_get(listaDeClustersARevisar,nClusterARevisar);
	clusterARevisar = pedirCluster(clusterARevisar->numeroCluster);
	encontrado = buscarFdtEntryEnCluster(entradaParcial,clusterARevisar,dir);

	}

	return encontrado;
}

int32_t buscarFdtEntryEnCluster(t_fdtCompleteEntry * entradaArchivo,t_cluster * clusterABuscar,char * nombreArchivo){
int32_t encontrado=0;
int32_t bloqueRevisado=0;
int32_t sectorRevisado=0;
t_fdtCompleteEntry * entradaArchivoAuxiliar;
int32_t bytesRevisados;

printf("En buscarFdtEntryEnCluster \n");
printf("Nombre Archivo: %s \n",nombreArchivo);
fflush(stdin);

	while (bloqueRevisado < clusterABuscar->bloques->elements_count && !encontrado) {
		t_bloque * bloqueARevisar = collection_list_get(clusterABuscar->bloques,bloqueRevisado);
		encontrado =buscarFdtEntryEnBloque(bloqueARevisar,entradaArchivo,nombreArchivo);
		bloqueRevisado++;


		}
return encontrado;
}


int32_t buscarFdtEntryEnBloque(t_bloque *bloqueARevisar,t_fdtCompleteEntry *entradaArchivo,char * nombreDeArchivo){
	int32_t encontrado = 0;
	int32_t sectorRevisado =0;

	printf("En buscarFdtEntryEnBloque \n");
	printf("Nombre Archivo: %s \n",nombreDeArchivo);
	fflush(stdin);

	while(sectorRevisado < pPfs.configArch.blockSize && !encontrado){
	t_sector * sectorARevisar = collection_list_get(bloqueARevisar->sectores,sectorRevisado);
		encontrado =buscarFdtEntryEnSector(sectorARevisar,entradaArchivo,nombreDeArchivo);
		sectorRevisado++;
	}
	return encontrado;
}

int32_t buscarFdtEntryEnSector(t_sector * sectorRevisado,t_fdtCompleteEntry * entradaArchivo, char * nombreDeArchivo) {
		int32_t encontrado = 0;
		int32_t bytesAnalizados = 0;
		t_fdtCompleteEntry * entradaAuxiliar;
		entradaAuxiliar = (t_fdtCompleteEntry *) malloc(sizeof(t_fdtCompleteEntry));
		t_fdtCompleteEntry * entradaArchivoTemp= (t_fdtCompleteEntry *) malloc(sizeof(t_fdtCompleteEntry));

		printf("En buscarFdtEntryEnBloque \n");
		printf("Nombre Archivo: %s \n",nombreDeArchivo);
		fflush(stdin);

		while ((!encontrado)&& (bytesAnalizados < pPfs.fat32.bootSector.bytesPerSector)) {
			memcpy(entradaAuxiliar, &sectorRevisado->data[bytesAnalizados],64);
			/*
			int e=0;
			while(e<512){
			printf("%c a",sectorRevisado->data[e]);
			e++;
			}
			*/
			fflush(stdin);

			if (longFdtEntry(entradaAuxiliar)) {
				entradaArchivoTemp->tieneEntradaLarga = 1;
				memcpy(&entradaArchivoTemp->entradaCorta,&entradaAuxiliar->entradaCorta, sizeof(t_fdtEntry));
				memcpy(&entradaArchivoTemp->entradaLarga,&entradaAuxiliar->entradaLarga,sizeof(t_fdtLongEntry));
				bytesAnalizados = bytesAnalizados + 64;;
			}
			else{
				entradaArchivoTemp->tieneEntradaLarga=0;
		memcpy(&entradaArchivoTemp->entradaCorta,&entradaAuxiliar->entradaLarga,sizeof(t_fdtEntry));
		bytesAnalizados = bytesAnalizados +32;
			}
			char * nombreArchivoBOBO;
			nombreArchivoBOBO= malloc (sizeof(14));
			encontrado = fdtEntryDeArchivo(nombreDeArchivo, entradaArchivoTemp);
			}

		if(encontrado){
//		entradaArchivo = (t_fdtCompleteEntry *) malloc(sizeof(t_fdtCompleteEntry));
			memcpy(&entradaArchivo->entradaCorta,&entradaArchivoTemp->entradaCorta, sizeof(t_fdtEntry));
			memcpy(&entradaArchivo->entradaLarga,&entradaArchivoTemp->entradaLarga,sizeof(t_fdtLongEntry));
			entradaArchivo->tieneEntradaLarga = entradaArchivoTemp->tieneEntradaLarga;
			free(entradaAuxiliar);
			free(entradaArchivoTemp);

		}else{
			free(entradaAuxiliar);
			free(entradaArchivoTemp);
		}
		return encontrado;

	}


/*
 * @NAME: longFdtEntry
 * @DESC: Pasandole una entrada completa esta analiza si es larga o no
 */
int32_t longFdtEntry(t_fdtEntry * entrada){
	return entrada->fileAtributes== FILE_ATTRIBUTE_LONG_FILE_ENTRY;
}

/*
 * @NAME: fdtEntryDeArchivo
 * @DESC: Devuelve 1 si el nombre del archivo es el mismo que tiene la entrada de la fdt
 */
int32_t fdtEntryDeArchivo(char *nombreDeArchivo, t_fdtCompleteEntry * entradaArchivo){
	int32_t encontrado;
	if(entradaArchivo->tieneEntradaLarga){
		char * nombreLargo = fdtEntryNombreArchivo(entradaArchivo);
		encontrado = !strcmp(nombreLargo,nombreDeArchivo);
	}
	else{
		char * nombreCorto= fdtEntryNombreArchivo(entradaArchivo);
		encontrado =  !strcmp(nombreCorto,nombreDeArchivo);
	}

	return encontrado;

	}

/*
 * @NAME: fdtEntryNombreArchivo
 * @DESC: Devuelve el nombre del archivo de la fdt
 */

//TODO, toma bien el "." del archivo?

char * fdtEntryNombreArchivo(char * entradaArchivoAnalizar){
	t_fdtEntry * entradaFdt = (t_fdtEntry *)entradaArchivoAnalizar;
	char * nombreArchivoBOBO;
	nombreArchivoBOBO= malloc (sizeof(14));

	char nombreArchivoUTF16[26];
	int i =0;
	int tamanioDeCadenaEnUTF16 = 26;
	char cadenaEnUTF8[tamanioDeCadenaEnUTF16/2];
	int tamanioDeCadenaEnUTF8 = 0;

	if(longFdtEntry(entradaFdt)){
	t_fdtCompleteEntry  entradaArchivo;
	memcpy(&entradaArchivo.entradaCorta,entradaArchivoAnalizar+32 ,32);
	memcpy(&entradaArchivo.entradaLarga,entradaArchivoAnalizar ,32);

	memcpy(nombreArchivoUTF16,entradaArchivo.entradaLarga.nameCharacters1,10);
	memcpy(nombreArchivoUTF16+10,entradaArchivo.entradaLarga.nameCharacters2,12);
	memcpy(nombreArchivoUTF16+22,entradaArchivo.entradaLarga.nameCharacters3,4);

	unicode_utf16_to_utf8_inbuffer(nombreArchivoUTF16, tamanioDeCadenaEnUTF16, cadenaEnUTF8, &tamanioDeCadenaEnUTF8);

	memcpy(nombreArchivoBOBO, cadenaEnUTF8,13);
	}
	else{

	memcpy(nombreArchivoBOBO,entradaArchivoAnalizar,8);

	}

	printf("Nombre archivoBOBO: %s \n",nombreArchivoBOBO);
	fflush(stdin);
	return nombreArchivoBOBO;

	}


int32_t listarDirectorio(char * path,t_list * archivosEnDirectorio){
	if(!strcmp(path,"/")){
		listarDirectorioRoot(archivosEnDirectorio);
	}
	return 1;
}

int32_t listarDirectorioRoot(t_list * archivosEnDirectorio){

}

t_list * buscarTodasLasFdtEntryEnCluster(t_cluster * cluster){
	t_list * listaDeEntradas;
	t_list * listaDeEntradasAux;


	int32_t bloqueRevisado=0;
	int32_t sectorRevisado=0;
	t_fdtCompleteEntry * entradaArchivoAuxiliar;
	int32_t bytesRevisados;
	listaDeEntradas = collection_list_create();
	int32_t cantidadEntradasDeBloqueAgregadas=0;

		while (bloqueRevisado < cluster->bloques->elements_count) {
			t_bloque * bloqueARevisar = collection_list_get(cluster->bloques,bloqueRevisado);
			listaDeEntradasAux =buscarTodasLasFdtEntryEnBloque(bloqueARevisar);
			while(listaDeEntradasAux->elements_count>cantidadEntradasDeBloqueAgregadas){
			collection_list_add(listaDeEntradas,collection_list_get(listaDeEntradasAux,cantidadEntradasDeBloqueAgregadas));
			cantidadEntradasDeBloqueAgregadas++;
			}
		bloqueRevisado++;
		cantidadEntradasDeBloqueAgregadas=0;
		}
	return listaDeEntradas;
}

t_list * buscarTodasLasFdtEntryEnBloque(t_bloque * bloque){

	int32_t sectorRevisado =0;
	t_list * listaDeEntradas;
	t_list * listaDeEntradasAux;
	int32_t  cantidadEntradasDeSectoresAgregadas=0;

	listaDeEntradas = collection_list_create();
	while(sectorRevisado < pPfs.configArch.blockSize){
	t_sector * sectorARevisar = collection_list_get(bloque->sectores,sectorRevisado);
		listaDeEntradasAux =buscarTodasLasFdtEntryEnSector(sectorARevisar);
		while(listaDeEntradasAux->elements_count>cantidadEntradasDeSectoresAgregadas){
		collection_list_add(listaDeEntradas,collection_list_get(listaDeEntradasAux,cantidadEntradasDeSectoresAgregadas));
		cantidadEntradasDeSectoresAgregadas++;
		}
		sectorRevisado++;
		cantidadEntradasDeSectoresAgregadas=0;
}
	free(listaDeEntradasAux);
	return listaDeEntradas;
}

t_list * buscarTodasLasFdtEntryEnSector(t_sector * sector){
		int32_t encontrado = 0;
		int32_t bytesAnalizados = 0;
		t_fdtCompleteEntry * entradaAuxiliar;
		t_fdtCompleteEntry * entradaArchivo;
		t_list * listaDeEntradas;

		entradaAuxiliar = (t_fdtCompleteEntry *)malloc(sizeof(t_fdtCompleteEntry));

		listaDeEntradas = collection_list_create();

		while ((bytesAnalizados < pPfs.fat32.bootSector.bytesPerSector)) {
			memcpy(entradaAuxiliar, &sector->data[bytesAnalizados],64);


			if (longFdtEntry(entradaAuxiliar)) {
				entradaArchivo = (t_fdtCompleteEntry *)malloc(sizeof(t_fdtCompleteEntry));
				entradaArchivo->tieneEntradaLarga = 1;
				memcpy(&entradaArchivo->entradaCorta,&entradaAuxiliar->entradaCorta, sizeof(t_fdtEntry));
				memcpy(&entradaArchivo->entradaLarga,&entradaAuxiliar->entradaLarga,sizeof(t_fdtLongEntry));
				bytesAnalizados = bytesAnalizados + 64;
			}
			else{
				entradaArchivo = (t_fdtCompleteEntry *)malloc(sizeof(t_fdtCompleteEntry));
				entradaArchivo->tieneEntradaLarga=0;
		memcpy(&entradaArchivo->entradaCorta,&entradaAuxiliar->entradaLarga,sizeof(t_fdtEntry));
		bytesAnalizados = bytesAnalizados +32;
			}
			if(!fdtDeleted(entradaArchivo)){
				collection_list_add(listaDeEntradas,entradaArchivo);
			}else{
				free(entradaArchivo);
				//TODO: Optimizar como fijarse si la entrada esta borrada, se ahorra tiempo.
			}

		}
		return listaDeEntradas;
}

int32_t fdtDeleted(char * entradaArchivo){

	return (entradaArchivo[0]==0xE5 || entradaArchivo[0]==0);
	/*
	if(entradaArchivo->tieneEntradaLarga){
		return ((entradaArchivo->entradaLarga.secuenceNumber=='E5')||
				(entradaArchivo->entradaLarga.secuenceNumber==0));
		return 1;
	}
	else{
		return ((entradaArchivo->entradaCorta.DOSFilename[0]=='E5')||
				(entradaArchivo->entradaCorta.DOSFilename[0]==0));
		return 1;
	}
	*/
}

/*
int32_t obtenerEntradasDePath(char * path, t_list * listaDeEntradas){



	fdtEntryDePath(path,fdtEntry,entradaCache);

	return 1;
}
*/

void escribirFat(void){
	uint32_t offset;
	uint32_t offsetBloques = pPfs.fat32.bootSector.reservedSectorCount / pPfs.configArch.blockSize;
	uint32_t cantidadBloquesAEscribir = pPfs.fat32.extendBios.sectorsFAT /pPfs.configArch.blockSize;

	int i =0;

		for (i=0; i < cantidadBloquesAEscribir; i++) {
			escribirBloque_v2(offsetBloques+i,pPfs.cacheArchivos.fat->tabla+i*bytesPerBlock());

		}
		pPfs.cacheArchivos.fat->modificado = 0;


}

void leerFat(void){
	pPfs.cacheArchivos.fat->tabla = (char *) malloc (pPfs.fat32.extendBios.sectorsFAT);
	uint32_t offsetBloques = pPfs.fat32.bootSector.reservedSectorCount / pPfs.configArch.blockSize;
	uint32_t cantidadBloquesALeer = pPfs.fat32.extendBios.sectorsFAT /pPfs.configArch.blockSize;
	int32_t i;

	for(i=0;i<cantidadBloquesALeer;i++){
		char * bloqueData;
		bloqueData = leerBloque(offsetBloques + i);
		memcpy(pPfs.cacheArchivos.fat->tabla + i*bytesPerBlock(),bloqueData,bytesPerBlock());
		free(bloqueData);
	}
pPfs.cacheArchivos.fat->modificado =0;
}

void tomarFat(void){
sem_wait(&pPfs.cacheArchivos.semaforo);
}
void liberarFat(void){
sem_post(&pPfs.cacheArchivos.semaforo);

}
//A REVISAR
/*
int32_t buscarEntradaLibreEnCluster(char * clusterData, int32_t * pos,int32_t * tamanio){
	int32_t encontrado =0;
	uint32_t bytesAnalizados = 0;
	t_fdtCompleteEntry * entradaAuxiliar;
	entradaAuxiliar = (t_fdtCompleteEntry *)malloc(sizeof(t_fdtCompleteEntry));
	t_fdtCompleteEntry *	entradaArchivo;
	while(!encontrado){

		while ((bytesAnalizados <bytesPerCluster())) {
					memcpy(&entradaAuxiliar->entradaLarga, &clusterData[bytesAnalizados],32);
					memcpy(&entradaAuxiliar->entradaCorta, &clusterData[bytesAnalizados+32],32);


					if (longFdtEntry(entradaAuxiliar)) {
						entradaArchivo = (t_fdtCompleteEntry *)malloc(sizeof(t_fdtCompleteEntry));
						entradaArchivo->tieneEntradaLarga = 1;
						memcpy(&entradaArchivo->entradaCorta,&entradaAuxiliar->entradaCorta, sizeof(t_fdtEntry));
						memcpy(&entradaArchivo->entradaLarga,&entradaAuxiliar->entradaLarga,sizeof(t_fdtLongEntry));
						bytesAnalizados = bytesAnalizados + 64;
					}
					else{
						entradaArchivo = (t_fdtCompleteEntry *)malloc(sizeof(t_fdtCompleteEntry));
						entradaArchivo->tieneEntradaLarga=0;
				memcpy(&entradaArchivo->entradaCorta,&entradaAuxiliar->entradaLarga,sizeof(t_fdtEntry));
				bytesAnalizados = bytesAnalizados +32;
					}
					if(!fdtDeleted(entradaArchivo)){
						collection_list_add(listaDeEntradas,entradaArchivo);
					}else{
						free(entradaArchivo);
						//TODO: Optimizar como fijarse si la entrada esta borrada, se ahorra tiempo.
					}

				}
				return listaDeEntradas;



	}


}

*/

void eliminarEntrada(t_cache_archivo * archivoCache){
	uint32_t nCluster = archivoCache->clusterContenido;
	char * clusterData = leerCluster(nCluster);

	tomarFat();
	pPfs.cacheArchivos.fat->tabla[nCluster]=0;
	pPfs.cacheArchivos.fat->modificado = 1;
	liberarFat();

	if(archivoCache->entradaDelArchivo->tieneEntradaLarga){
		//Si entra en este if quiere decir que la entrada esta partida entre dos clusters
		if(archivoCache->posicionByteEnClusterPadre == bytesPerCluster()-32){
			if(clusterData[archivoCache->posicionByteEnClusterPadre]==0){
				clusterData[archivoCache->posicionByteEnClusterPadre]=0;
			}else {
				clusterData[archivoCache->posicionByteEnClusterPadre]=0xE5;
			}
			//TODO, lo pusieron de distinta manera
			escribirClusterV2(clusterData,nCluster);

		free(clusterData);
		nCluster = clusterNConcatenadoDe(nCluster,1);
		clusterData = leerCluster(nCluster);
		if(clusterData==0){
					clusterData=0;
				}else {
					clusterData=0xE5;
				}
		escribirClusterV2(clusterData,nCluster);
		free(clusterData);
		}
		//Entra aca si es entrada larga y esta toda la informacion en el clusterContenido
		else{
			if(clusterData[archivoCache->posicionByteEnClusterPadre]==0){
							clusterData[archivoCache->posicionByteEnClusterPadre]=0;
						}else {
							clusterData[archivoCache->posicionByteEnClusterPadre]=0xE5;
						}
			if(clusterData[archivoCache->posicionByteEnClusterPadre+32]==0){
							clusterData[archivoCache->posicionByteEnClusterPadre+32]=0;
						}else {
							clusterData[archivoCache->posicionByteEnClusterPadre+32]=0xE5;
						}
			}

		}
	//Si entra aca es porque es entrada corta LA PUTA QUE TE PARIO RICHIE
	if(clusterData[archivoCache->posicionByteEnClusterPadre]==0){
							clusterData[archivoCache->posicionByteEnClusterPadre]=0;
						}else {
							clusterData[archivoCache->posicionByteEnClusterPadre]=0xE5;
						}
	escribirClusterV2(clusterData,nCluster);
	free(clusterData);
}



char *pasarUTF8aUTF16(char * cadenaEnUTF8){
	int tamanioDeCadenaEnUTF16 = 26;
	char * cadenaEnUTF16 = (char *) malloc(tamanioDeCadenaEnUTF16);
	char  tamanioCadenaEnEnUTF8=tamanioDeCadenaEnUTF16/2;
	int tamanioDeCadenaEnUTF8 = 0;


		unicode_utf8_to_utf16_inbuffer(cadenaEnUTF8, tamanioCadenaEnEnUTF8, cadenaEnUTF16, &tamanioDeCadenaEnUTF16);

return cadenaEnUTF16;

}

//busca todas las entradas de fdt o una en especial de un directorio
t_list * buscarFdtEntrysEnDirectorio(t_cache_archivo * archivoDirectorio, char * path,int32_t opcion){
	int32_t encontrado=0;
	t_list * listaClustersDeDirectorio;

	listaClustersDeDirectorio = clusterConcatenadosDeCluster(archivoDirectorio->entradaDelArchivo->entradaCorta.startCluster);
	uint32_t nClusterDeDirectorio =0;
	t_list * listaFdtEntrysEncontrados;
	char * clusterData;
	uint32_t posicion =0;


	while(!encontrado && nClusterDeDirectorio < listaClustersDeDirectorio->elements_count){
		uint32_t * clusterAAnalizar = collection_list_get(listaClustersDeDirectorio,nClusterDeDirectorio);
		//pedirCluster//messi2
		clusterData = leerCluster(*clusterAAnalizar,archivoDirectorio);
		listaFdtEntrysEncontrados = buscarFdtEntry(clusterData,opcion,path,&posicion);

		if(opcion){
			if(listaFdtEntrysEncontrados->elements_count ==1){
				encontrado=1;
				free(clusterData);
			}
		}
		nClusterDeDirectorio++;
	}
	return listaFdtEntrysEncontrados;

}

//QUEDA si le paso la opcion 0 quiere decir buscar todas las entradas, si le paso la opcion 1 una en especial
t_list * buscarFdtEntry(char * clusterData,int32_t opcion,char *pathABuscar,uint32_t * posicion ){
		int32_t encontrado = 0;
		int32_t bytesAnalizados = 0;
		t_fdtEntry * entradaAuxiliar;
		t_fdtCompleteEntry * entradaArchivo;
		t_list * listaDeEntradas;


		encontrado = opcion;

		entradaAuxiliar = (t_fdtEntry *)malloc(sizeof(t_fdtEntry));

		listaDeEntradas = collection_list_create();

		while ((bytesAnalizados < bytesPerCluster()) && !encontrado) {
			entradaAuxiliar = &clusterData[bytesAnalizados];
			if(!fdtDeleted(entradaAuxiliar)){
				if (longFdtEntry(entradaAuxiliar)) {
						if(opcion){//si esta activada la opcion de busqueda unica
							if(strcmp(fdtEntryNombreArchivo((char *)entradaAuxiliar),pathABuscar)){
								continue; //son distintos siga
							}else{
								encontrado=1;
							}

						}

								entradaArchivo = (t_fdtCompleteEntry *)malloc(sizeof(t_fdtCompleteEntry));
								entradaArchivo->tieneEntradaLarga = 1;
								memcpy(&entradaArchivo->entradaCorta,&clusterData[bytesAnalizados+32], sizeof(t_fdtEntry));
								memcpy(&entradaArchivo->entradaLarga,&clusterData[bytesAnalizados],sizeof(t_fdtLongEntry));
								bytesAnalizados = bytesAnalizados + 64;
							}//tata
							else{
								entradaArchivo = (t_fdtCompleteEntry *)malloc(sizeof(t_fdtCompleteEntry));
								entradaArchivo->tieneEntradaLarga=0;
						memcpy(&entradaArchivo->entradaCorta,&clusterData[bytesAnalizados],sizeof(t_fdtEntry));
						bytesAnalizados = bytesAnalizados +32;

							}

				collection_list_add(listaDeEntradas,entradaArchivo);
			}else{
				bytesAnalizados = bytesAnalizados +32;
			}
}
		*posicion = bytesAnalizados;
		return listaDeEntradas;

}

uint32_t lsDir(char * path,t_list * listaEntradas){
//ASUMO QUE YA ESTA EN LA CACHE, ESTA BIEN??, por las dudas le meto que si no lo encuentra devuelve que no lo encontro
	t_cache_archivo *cacheDeDir;
	uint32_t encontrado = buscarEnCachePath(path,cacheDeDir);

}
